#pragma once

#include <string>
#include "api/peer_connection_interface.h"
#include "api/scoped_refptr.h"
#include "api/media_stream_interface.h"
#include "pc/stream_collection.h"
#include "peer_connection_dependency_factory.h"
#include "rtc_client/observer/functional_observer.h"
#include "rtc_client/rtc_wrapper.h"

namespace ohosrtc {

class SignalingClient;
using OHOSMediaStreamPtr = rtc::scoped_refptr<ohoswebrtc::OHOSMediaStreamInterface>;
using OnAddStreamEvent = std::function<void(OHOSMediaStreamPtr stream)>;
using OnRemoveStreamEvent = std::function<void(OHOSMediaStreamPtr stream)>;

//webrtc peer_connection wrapper
class PeerConnectionChannel : public ohoswebrtc::OHOSPeerConnectionObserver, public std::enable_shared_from_this<PeerConnectionChannel>  {
  public:
    explicit PeerConnectionChannel(PeerConnectionChannelConfiguration configuration, 
            std::shared_ptr<PeerConnectionDependencyFactory> pcd_factory,
            std::shared_ptr<SignalingClient> signaling_client);
    ~PeerConnectionChannel();
  
    static std::shared_ptr<PeerConnectionChannel> Create(PeerConnectionChannelConfiguration configuration, 
            std::shared_ptr<PeerConnectionDependencyFactory> pcd_factory,
            std::shared_ptr<SignalingClient> signaling_client);
    //use to make call
    void CreateP2pOffer(OHOSLocalStreamPtr ohos_local_stream);
    //use to accept call
    void CreateP2pAnswer(OHOSLocalStreamPtr local_stream);
    //handle pc close
    void Close();
    // add stream to pc
    void AddStream(OHOSMediaStreamPtr media_stream);
    // remove stream to pc
    void RemoveStream(OHOSMediaStreamPtr media_stream);
    // sdp process
    void CreateOffer();
    // sdp process
    void CreateAnswer();
    // sdp process
    void SetLocalDescription(SDP* desc);
    // sdp process
    void SetRemoteDescription(SDP* desc);
    void SetRemoteIceCandidate(IceCandidate* ice_candidate);
    // set stream event handler
	  void SetStreamEventHandler(OnAddStreamEvent onAddStream, OnRemoveStreamEvent onRemoveStream);
    // pc sdp event observer
    void OnCreateSdpSuccess(SDP *desc);
    void OnCreateSdpFailure(const std::string error);
    void OnSetLocalSdpCompletion(const webrtc::RTCError error);
    void OnSetRemoteSdpCompletion(const webrtc::RTCError error);
  
    //ohoswebrtc::OHOSPeerConnectionObserver
    void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) override;
    void OnAddStream(rtc::scoped_refptr<ohoswebrtc::OHOSMediaStreamInterface> stream) override;
    void OnRemoveStream(rtc::scoped_refptr<ohoswebrtc::OHOSMediaStreamInterface> stream) override;
    void OnDataChannel(rtc::scoped_refptr<ohoswebrtc::OHOSDataChannelInterface> data_channel) override;
    void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) override;
    void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) override;
    void OnIceCandidate(const webrtc::IceCandidateInterface *candidate) override;
    void OnAddTrack(rtc::scoped_refptr<ohoswebrtc::OHOSRtpReceiverInterface> receiver,
                    const std::vector<rtc::scoped_refptr<ohoswebrtc::OHOSMediaStreamInterface>> &streams) override;
  
    // set local stream for pc and save private ohos_local_stream_
    void setLocalStream(OHOSLocalStreamPtr stream);
    std::weak_ptr<PeerConnectionChannel> weak_this_;
    std::string id;
    OHOSPeerConnectionPtr GetPeerConnection();
  
  private:
    void InitPeerConnection();
    FunctionalCreateSdpObserver *MakeCreateSdpObserver(const std::weak_ptr<PeerConnectionChannel> &weak_this);
    rtc::scoped_refptr<webrtc::SetLocalDescriptionObserverInterface> MakeSetLocalDescriptionObserver(const std::weak_ptr<PeerConnectionChannel> &weak_this);
    rtc::scoped_refptr<webrtc::SetRemoteDescriptionObserverInterface> MakeSetRemoteDescriptionObserver(const std::weak_ptr<PeerConnectionChannel> &weak_this);
    PeerConnectionChannelConfiguration configuration_;
    OHOSPeerConnectionPtr ohos_peer_connection_;

    OHOSLocalStreamPtr ohos_local_stream_;
    std::shared_ptr<PeerConnectionDependencyFactory> pcd_factory_;
    std::shared_ptr<SignalingClient> signaling_client_;
	  OnAddStreamEvent on_add_stream_event_;
	  OnRemoveStreamEvent on_remove_stream_event_;
    std::unordered_map<std::string, std::vector<rtc::scoped_refptr<ohoswebrtc::OHOSRtpSenderInterface>>> stream_sends_;
};

} // namespace ohosrtc